using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Messages;
using CRMCustom.Parser;
using CRMCustom.WebService;
using CRMCustom.WordDocuments;

namespace CRMCustom
{
    public partial class OrganizationControl : UserControl
    {
        private const string SYSTEM_ERROR_MESSAGE = "The selected item is required for the Microsoft Dynamics CRM system to work correctly.";
        private const string SYSTEM_ERROR_CAPTION = "Microsoft Dynamics CRM";
        private CrmViewType m_currentView;
        private CrmConnection m_con;
        private CrmOrganization m_org;
        private MainForm m_mainForm;
        private static CrmEntitySorter m_entitySorter;
        private Dictionary<Guid, Guid> m_stepEntityMap = new Dictionary<Guid, Guid>();
        private Dictionary<string, CrmTreeNode> m_rootNodeList = null;
        private Dictionary<Guid, Guid> m_viewNodeList = null;
        private Dictionary<Guid, Guid> m_stepParentList = null;

        public OrganizationControl(CrmOrganization org, MainForm mainForm)
        {
            //if (org == null)
            //{
            //    throw new ArgumentNullException("org");
            //}
            //else if (org.Connection == null)
            //{
            //    throw new ArgumentNullException("org.Connection");
            //}
            this.m_mainForm = mainForm;
            this.m_org = org;
            InitializeComponent();
        }


        #region Control Event Handlers
        /*
		private void toolAssemblyRegister_Click(object sender, EventArgs e)
		{
			PluginRegistrationForm regForm = new PluginRegistrationForm(this.Organization, this, null);
			regForm.ShowDialog(this.ParentForm);
		}
		private void toolServiceEndpointRegister_Click(object sender, EventArgs e)
		{
			ServiceBusConfigForm serviceBusConfigForm = new ServiceBusConfigForm(this.Organization, this, null);
			serviceBusConfigForm.ShowDialog();
		}
		private void toolStepRegister_Click(object sender, EventArgs e)
		{
			//Check if we can extract a plugin from the Tree
			CrmPlugin plugin = null;
			CrmServiceEndpoint serviceEndpoint = null;

			if (trvExcelSheetContents.SelectedNode != null)
			{
				Guid pluginId;
				Guid serviceEndpointId = Guid.Empty;
				switch (trvExcelSheetContents.SelectedNode.NodeType)
				{
					case CrmTreeNodeType.Assembly:
					case CrmTreeNodeType.Message:
					case CrmTreeNodeType.MessageEntity:

						pluginId = Guid.Empty;
						break;

					case CrmTreeNodeType.Plugin:
					case CrmTreeNodeType.WorkflowActivity:

						pluginId = trvExcelSheetContents.SelectedNode.NodeId;
						break;
					case CrmTreeNodeType.Step:

						pluginId = ((CrmPluginStep)trvExcelSheetContents.SelectedNode).PluginId;
						break;
					case CrmTreeNodeType.Image:

						pluginId = ((CrmPluginImage)trvExcelSheetContents.SelectedNode).PluginId;
						break;
					case CrmTreeNodeType.ServiceEndpoint:

						pluginId = ((CrmServiceEndpoint)trvExcelSheetContents.SelectedNode).PluginId;
						serviceEndpointId = ((CrmServiceEndpoint)trvExcelSheetContents.SelectedNode).NodeId;
						break;
					default:
						throw new NotImplementedException("NodeType = " + trvExcelSheetContents.SelectedNode.NodeType.ToString());
				}

				if (Guid.Empty != pluginId)
				{
					plugin = this.m_org.Plugins[pluginId];
				}
				if (Guid.Empty != serviceEndpointId)
				{
					serviceEndpoint = this.m_org.ServiceEndpoints[serviceEndpointId];
				}
			}

			StepRegistrationForm regForm = new StepRegistrationForm(this.Organization, this, plugin, null, serviceEndpoint);
			regForm.ShowDialog();
		}

		private void trvPlugins_SelectionChanged(object sender, CrmTreeNodeTreeEventArgs e)
		{
			this.SelectItem(e.Node);
		}

		private void toolUnregister_Click(object sender, EventArgs e)
		{
			if (trvExcelSheetContents.SelectedNode == null)
			{
				return;
			}
			else if (this.IsNodeSystemItem(trvExcelSheetContents.SelectedNode))
			{
				this.ShowSystemItemError("It cannot be unregistered.");
				return;
			}

			Guid nodeId = trvExcelSheetContents.SelectedNode.NodeId;
			if (MessageBox.Show("Are you sure you want to unregister this item?", "Unregister",
				MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
			{
				this.Enabled = false;
				this.MainForm.EnableToolBar(false);

				try
				{
					StringBuilder builder = new StringBuilder();
					foreach (KeyValuePair<string, int> stat in RegistrationHelper.Unregister(this.m_org,
						this.MainForm.ProgressIndicator, (ICrmEntity)this.trvExcelSheetContents.SelectedNode))
					{
						builder.AppendLine(string.Format("{0} {1} Unregistered Successfully", stat.Value, stat.Key));
					}

					this.trvExcelSheetContents.RemoveNode(this.trvExcelSheetContents.SelectedNode.NodeId);

					MessageBox.Show(builder.ToString(), "Unregister", MessageBoxButtons.OK, MessageBoxIcon.Information);
				}
				catch (Exception ex)
				{
					ErrorMessage.ShowErrorMessageBox(this, "Unable to unregister this item an error occurred.", "Unregister Error", ex);
				}
				finally
				{
					if (trvExcelSheetContents.HasNode(nodeId))
					{
						trvExcelSheetContents.RefreshNode(nodeId, true);
						this.SelectItem(trvExcelSheetContents.SelectedNode);
					}

					this.Enabled = true;
					this.MainForm.EnableToolBar(true);
				}

				trvExcelSheetContents.Focus();
			}
			else
			{
				trvExcelSheetContents.Focus();
				return;
			}
		}

		private void toolEnable_Click(object sender, EventArgs e)
		{
			if (trvExcelSheetContents.SelectedNode.NodeType != CrmTreeNodeType.Step)
			{
				return;
			}
			else if (this.IsNodeSystemItem(trvExcelSheetContents.SelectedNode))
			{
				this.ShowSystemItemError("The step cannot be enabled or disabled.");
				return;
			}

			CrmPluginStep step = (CrmPluginStep)trvExcelSheetContents.SelectedNode;
			string captionItem, messageItem;
			if (step.Enabled)
			{
				captionItem = "Disable";
				messageItem = "disable";
			}
			else
			{
				captionItem = "Enable";
				messageItem = "enable";
			}

			if (MessageBox.Show(string.Format("Are you sure you want to {0} this step?", messageItem),
				string.Format("{0} Step", captionItem),
				MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)
			{
				return;
			}

			this.Enabled = false;
			try
			{
				RegistrationHelper.UpdateStepStatus(this.m_org, step.StepId, !step.Enabled);
				step.Enabled = !step.Enabled;
				UpdateEnableButton(step.Enabled);
				trvExcelSheetContents.RefreshNode(trvExcelSheetContents.SelectedNode.NodeId);

				MessageBox.Show(string.Format("Step {0}d successfully.", messageItem),
					string.Format("{0} Step", captionItem), MessageBoxButtons.OK, MessageBoxIcon.Information);
			}
			catch (Exception ex)
			{
				ErrorMessage.ShowErrorMessageBox(this,
					string.Format("Unable to {0} this item at ths time. An error occurred.", messageItem),
					string.Format("{0} Step", captionItem), ex);
			}
			finally
			{
				this.Enabled = true;
			}
		}

		private void toolUpdate_Click(object sender, EventArgs e)
		{
			if (this.IsNodeSystemItem(trvExcelSheetContents.SelectedNode))
			{
				this.ShowSystemItemError("The assembly cannot be updated.");
				return;
			}

			switch (trvExcelSheetContents.SelectedNode.NodeType)
			{
				case CrmTreeNodeType.ServiceEndpoint:
					{
						ServiceBusConfigForm serForm = new ServiceBusConfigForm(this.Organization, this, (CrmServiceEndpoint)trvExcelSheetContents.SelectedNode);
						serForm.ShowDialog();
					}
					break;
				case CrmTreeNodeType.Assembly:
					{
						PluginRegistrationForm regForm = new PluginRegistrationForm(this.Organization, this, (CrmPluginAssembly)trvExcelSheetContents.SelectedNode);
						regForm.ShowDialog(this.ParentForm);
					}
					break;
				case CrmTreeNodeType.Step:
					{
						CrmPluginStep step = (CrmPluginStep)trvExcelSheetContents.SelectedNode;
						CrmPlugin plugin = this.m_org[step.AssemblyId][step.PluginId];
						CrmServiceEndpoint serviceEndpoint = null;
						if (step.ServiceBusConfigurationId != Guid.Empty)
						{
							serviceEndpoint = this.m_org.ServiceEndpoints[step.ServiceBusConfigurationId];
						}
						StepRegistrationForm regForm = new StepRegistrationForm(this.Organization, this, plugin, step, serviceEndpoint);
						regForm.ShowDialog();
					}
					break;
				case CrmTreeNodeType.Image:
					{
						ImageRegistrationForm regForm = new ImageRegistrationForm(this.m_org, this,
							trvExcelSheetContents.RootNodes, (CrmPluginImage)trvExcelSheetContents.SelectedNode, trvExcelSheetContents.SelectedNode.NodeId);
						regForm.ShowDialog();
					}
					break;
				default:
					throw new NotImplementedException("NodeType = " + trvExcelSheetContents.SelectedNode.NodeType.ToString());
			}

			ICrmTreeNode node = trvExcelSheetContents.SelectedNode;
			if (node != null)
			{
				trvPlugins_SelectionChanged(sender, new CrmTreeNodeTreeEventArgs(node, TreeViewAction.Unknown));
			}
		}

		private int m_dataRowIndex = -1;
		private Guid m_dataRowId = Guid.Empty;
		private void grvData_RowEnter(object sender, DataGridViewCellEventArgs e)
		{
			if (e.RowIndex == m_dataRowIndex)
			{
				return;
			}
			this.m_dataRowIndex = e.RowIndex;

			Guid rowId = (Guid)grvData.Rows[m_dataRowIndex].Cells["Id"].Value;
			this.m_dataRowId = rowId;

			//Check for special cases
			switch (trvExcelSheetContents.SelectedNode.NodeType)
			{
				case CrmTreeNodeType.Message:
				case CrmTreeNodeType.MessageEntity:

					//The Id presented in the DataGrid is not the id of the node in the tree
					if (this.m_viewNodeList.ContainsKey(rowId))
					{
						this.m_dataRowId = this.m_viewNodeList[rowId];
					}
					break;
			}
		}

		private void grvData_DoubleClick(object sender, EventArgs e)
		{
			if (trvExcelSheetContents.HasNode(this.m_dataRowId))
			{
				trvExcelSheetContents.SelectedNode = trvExcelSheetContents[this.m_dataRowId];
			}
		}

		private void toolImageRegister_Click(object sender, EventArgs e)
		{
			Guid nodeId = Guid.Empty;
			if (trvExcelSheetContents.SelectedNode != null && trvExcelSheetContents.SelectedNode.NodeType != CrmTreeNodeType.Image)
			{
				nodeId = trvExcelSheetContents.SelectedNode.NodeId;
			}

			// TODO : Ajith
			// Do Validations if the Image is valid on the Step -Message and then Launch the Wizard

			ImageRegistrationForm regForm = new ImageRegistrationForm(this.m_org, this, trvExcelSheetContents.RootNodes, null, nodeId);
			regForm.ShowDialog();
		}

		private void toolView_Click(object sender, EventArgs e)
		{
			if (sender != null && sender.GetType().IsSubclassOf(typeof(ToolStripItem)))
			{
				ToolStripItem item = (ToolStripItem)sender;
				if (item.Tag != null && item.Tag.GetType() == typeof(CrmViewType))
				{
					propGridEntity.SelectedObject = null;
					this.LoadNodes((CrmViewType)item.Tag);
				}
			}
		}

		private void toolRefresh_Click(object sender, EventArgs e)
		{
			this.Enabled = false;
			try
			{
				propGridEntity.SelectedObject = null;

				OrganizationHelper.RefreshConnection(this.m_org,
					this.m_mainForm.LoadMessages(this.m_org), this.m_mainForm.ProgressIndicator);

				this.LoadNodes();
			}
			catch (Exception ex)
			{
				ErrorMessage.ShowErrorMessageBox(this, "Unable to the refresh the organization. Connection must close.", "Connection Error", ex);
				((OrganizationsForm)this.ParentForm).CloseOrganizationTab(this.m_org.Connection.ConnectionId,
					this.m_org.OrganizationId);
				return;
			}
			finally
			{
				this.Enabled = true;
			}
		}
        
		private void trvPlugins_DoubleClick(object sender, CrmTreeNodeEventArgs e)
		{
			if (toolUpdate.Visible && toolUpdate.Enabled)
			{
				trvExcelSheetContents.SelectedNode = e.Node;
				if (toolUpdate.Visible && toolUpdate.Enabled)
				{
					this.toolUpdate_Click(sender, e);
				}
			}
		}

		private void trvPlugins_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Enter && toolUpdate.Enabled && toolUpdate.Visible)
			{
				toolUpdate_Click(sender, e);
			}
		}

		private void toolSearch_Click(object sender, EventArgs e)
		{
			SearchForm searchForm = new SearchForm(Organization, this, trvExcelSheetContents.RootNodes, trvExcelSheetContents.SelectedNode);
			searchForm.ShowDialog(this);
		}

		private void trvPlugins_NodeRemoved(object sender, CrmTreeNodeEventArgs e)
		{
			switch (e.Node.NodeType)
			{
				case CrmTreeNodeType.Step:
					{
						Guid stepId = e.Node.NodeId;
						if (null != this.m_stepParentList && this.m_stepParentList.ContainsKey(stepId))
						{
							CrmTreeNode node = (CrmTreeNode)trvExcelSheetContents[this.m_stepParentList[stepId]];
							node.RemoveChild(stepId);
							this.m_stepParentList.Remove(stepId);

							this.RemoveCrmTreeNodesCascadeUp(node);
						}
					}
					break;
				default:
					return;
			}

			if (null == trvExcelSheetContents.SelectedNode)
			{
				propGridEntity.SelectedObject = null;
			}
		}
        
		private void btnSave_Click(object sender, EventArgs e)
		{
			try
			{
				if (this.trvExcelSheetContents != null && this.trvExcelSheetContents.SelectedNode != null)
				{
					switch (this.trvExcelSheetContents.SelectedNode.NodeType)
					{
						case CrmTreeNodeType.Assembly:
							CrmPluginAssembly assembly = (CrmPluginAssembly)this.trvExcelSheetContents.SelectedNode;
							RegistrationHelper.UpdateAssembly(m_org, assembly.Description, assembly.AssemblyId);
							trvExcelSheetContents.RefreshNode(assembly.AssemblyId, false, false);
							MessageBox.Show("Assembly has been updated successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
							break;
						case CrmTreeNodeType.Plugin:
						case CrmTreeNodeType.WorkflowActivity:
							CrmPlugin plugin = (CrmPlugin)this.trvExcelSheetContents.SelectedNode;
							RegistrationHelper.UpdatePlugin(m_org, plugin);
							trvExcelSheetContents.RefreshNode(plugin.PluginId, false, false);
							MessageBox.Show("Plug-in has been updated successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
							break;
						default:
							MessageBox.Show("A valid object has not been selected.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
							break;
					}
				}
				else
				{
					MessageBox.Show("A valid object has not been selected.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
				}
			}
			catch (Exception ex)
			{
				ErrorMessage.ShowErrorMessageBox(this, "Unable to Update the Assembly /Plugin due to an error.", "Update", ex);
			}
		}

		#endregion

		#region Properties
		public IComparer<ICrmTreeNode> CrmTreeNodeSorter
		{
			get
			{
				return m_entitySorter;
			}
		}

		public MainForm MainForm
		{
			get
			{
				return this.m_mainForm;
			}
		}

		public CrmConnection Connection
		{
			get
			{
				return this.m_con;
			}
		}

		public CrmOrganization Organization
		{
			get
			{
				return this.m_org;
			}
		}

        /*
		public bool IsAutoExpanded
		{
			get
			{
				return this.trvExcelSheetContents.AutoExpand;
			}
		}
        */
        #endregion

        #region Public Methods
        /*
		public void AddServiceEndpoint(CrmServiceEndpoint serviceEndpoint)
		{
			if (serviceEndpoint == null)
			{
				throw new ArgumentNullException("serviceEndpoint");
			}

			if (this.m_currentView == CrmViewType.Assembly)
			{
				this.trvExcelSheetContents.AddNode(Guid.Empty, serviceEndpoint);
			}
		}
		public void AddAssembly(CrmPluginAssembly assembly)
		{
			if (assembly == null)
			{
				throw new ArgumentNullException("assembly");
			}

			if (this.m_currentView == CrmViewType.Assembly)
			{
				this.trvExcelSheetContents.AddNode(Guid.Empty, assembly);
			}
		}

		public void RefreshServiceEndpoint(CrmServiceEndpoint serviceEndpoint)
		{
			if (serviceEndpoint == null)
			{
				throw new ArgumentNullException("serviceEndpoint");
			}

			this.trvExcelSheetContents.RefreshNode(serviceEndpoint.NodeId, true);
			this.SelectItem(this.trvExcelSheetContents.SelectedNode);
		}
		public void RefreshAssembly(CrmPluginAssembly assembly, bool reloadChildren)
		{
			if (assembly == null)
			{
				throw new ArgumentNullException("assembly");
			}

			if (this.m_currentView == CrmViewType.Assembly)
			{
				this.trvExcelSheetContents.RefreshNode(assembly.NodeId, reloadChildren);
				this.SelectItem(this.trvExcelSheetContents.SelectedNode);
			}
		}

		public void RemoveAssembly(Guid assemblyId)
		{
			if (this.m_currentView == CrmViewType.Assembly)
			{
				this.trvExcelSheetContents.RemoveNode(assemblyId);
				this.SelectItem(trvExcelSheetContents.SelectedNode);
			}
		}

		public void AddPlugin(CrmPlugin reg)
		{
			if (reg == null)
			{
				throw new ArgumentNullException("reg");
			}

			if (this.m_currentView == CrmViewType.Assembly)
			{
				this.trvExcelSheetContents.AddNode(reg.AssemblyId, reg);
				if (trvExcelSheetContents.SelectedNode != null && trvExcelSheetContents.SelectedNode.NodeId == reg.AssemblyId)
				{
					this.SelectItem(trvExcelSheetContents.SelectedNode);
				}
			}
		}

		public void RefreshPlugin(CrmPlugin plugin)
		{
			if (plugin == null)
			{
				throw new ArgumentNullException("plugin");
			}

			if (this.m_currentView == CrmViewType.Assembly)
			{
				this.trvExcelSheetContents.RefreshNode(plugin.NodeId, true);
				this.SelectItem(this.trvExcelSheetContents.SelectedNode);
			}
		}

		public void RemovePlugin(Guid pluginId)
		{
			if (this.m_currentView == CrmViewType.Assembly)
			{
				this.trvExcelSheetContents.RemoveNode(pluginId);
				this.SelectItem(trvExcelSheetContents.SelectedNode);
			}
		}

		public void AddStep(CrmPluginStep step)
		{
			if (step == null)
			{
				throw new ArgumentNullException("step");
			}

			Guid parentId;
			switch (this.m_currentView)
			{
				case CrmViewType.Assembly:
					if (step.ServiceBusConfigurationId == Guid.Empty)
					{
						parentId = step.PluginId;
					}
					else
					{
						parentId = step.ServiceBusConfigurationId;
					}

					break;
				case CrmViewType.Entity:
				case CrmViewType.Message:
					parentId = CreateCrmTreeNodes(this.m_currentView, step.MessageId, step.MessageEntityId, true).NodeId;

					//Add to the step parent id list
					if (!this.m_stepParentList.ContainsKey(step.StepId))
					{
						this.m_stepParentList.Add(step.StepId, parentId);
					}

					//Add to the CrmTreeNode
					((CrmTreeNode)trvExcelSheetContents[parentId]).AddChild(step);
					break;
				default:
					throw new NotImplementedException("View = " + this.m_currentView.ToString());
			}

			this.trvExcelSheetContents.AddNode(parentId, step);
			if (trvExcelSheetContents.SelectedNode != null && trvExcelSheetContents.SelectedNode.NodeId == parentId)
			{
				this.SelectItem(trvExcelSheetContents.SelectedNode);
			}
		}

		public void RefreshStep(CrmPluginStep step)
		{
			if (step == null)
			{
				throw new ArgumentNullException("step");
			}

			this.trvExcelSheetContents.RefreshNode(step.NodeId, true);
			this.SelectItem(this.trvExcelSheetContents.SelectedNode);
		}

		public void RemoveStep(Guid stepId)
		{
			CrmPluginStep step = (CrmPluginStep)trvExcelSheetContents[stepId];

			this.trvExcelSheetContents.RemoveNode(stepId);
			this.SelectItem(trvExcelSheetContents.SelectedNode);
		}

		public void AddImage(CrmPluginImage image)
		{
			if (image == null)
			{
				throw new ArgumentNullException("image");
			}

			this.trvExcelSheetContents.AddNode(image.StepId, image);
			if (trvExcelSheetContents.SelectedNode != null && trvExcelSheetContents.SelectedNode.NodeId == image.StepId)
			{
				this.SelectItem(trvExcelSheetContents.SelectedNode);
			}
		}

		public void RefreshImage(CrmPluginImage image)
		{
			if (image == null)
			{
				throw new ArgumentNullException("image");
			}

			this.trvExcelSheetContents.RefreshNode(image.NodeId, true);
			this.SelectItem(this.trvExcelSheetContents.SelectedNode);
		}

		public void RemoveImage(Guid imageId)
		{
			this.trvExcelSheetContents.RemoveNode(imageId);
			this.SelectItem(trvExcelSheetContents.SelectedNode);
		}

		public bool IsNodeSystemItem(ICrmTreeNode node)
		{
			if (node != null)
			{
				return ((ICrmEntity)node).IsSystemCrmEntity;
			}
			else
			{
				return false;
			}
		}

		public void ShowSystemItemError(string text)
		{
			if (text == null)
			{
				MessageBox.Show(SYSTEM_ERROR_MESSAGE, SYSTEM_ERROR_CAPTION, MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			else
			{
				MessageBox.Show(string.Format("{0}\n{1}", SYSTEM_ERROR_MESSAGE, text),
					SYSTEM_ERROR_CAPTION, MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}
       
		public void SelectNode(Guid nodeId)
		{
			if (!trvExcelSheetContents.HasNode(nodeId))
			{
				throw new ArgumentException("Node is not in the tree", "nodeId");
			}

			trvExcelSheetContents.SelectedNode = trvExcelSheetContents[nodeId];
		}

		public void UpdateAutoExpand(bool newValue)
		{
			trvExcelSheetContents.AutoExpand = newValue;
		}*/
        #endregion

        #region Private Helper Methods
        /*
		private void SelectItem(ICrmTreeNode node)
		{
			//Reset the visibility and enabled properties because we don't what is enabled
			this.toolUpdate.Visible = false;
			this.mnuContextNodeUpdate.Visible = false;

			this.toolEnable.Visible = false;
			this.mnuContextNodeEnable.Visible = false;

			bool isSystemNode = this.IsNodeSystemItem(trvExcelSheetContents.SelectedNode);
			if (node == null)
			{
				mnuContextNodeUnregister.Enabled = false;
				toolUnregister.Enabled = false;
				mnuContextNodeUnregister.Enabled = false;
				return;
			}
			else
			{
				//It should only be possible to unregister non-system components
				mnuContextNodeUnregister.Enabled = !isSystemNode;
				toolUnregister.Enabled = !isSystemNode;
			}

			DataTable gridTable = null;
			switch (node.NodeType)
			{
				case CrmTreeNodeType.ServiceEndpoint:
					{
						CrmServiceEndpoint serviceEndpoint = (CrmServiceEndpoint)node;

						this.toolUpdate.Visible = true;
						this.mnuContextNodeUpdate.Visible = true;
						btnSave.Enabled = false;
						//Load the data table and display information
						gridTable = OrganizationHelper.CreateDataTable<CrmPluginStep>(CrmPluginStep.Columns, serviceEndpoint.Steps);
					}
					break;
				case CrmTreeNodeType.Assembly:
					if (!isSystemNode)
					{
						CrmPluginAssembly assembly = (CrmPluginAssembly)node;

						this.toolUpdate.Visible = true;
						this.mnuContextNodeUpdate.Visible = true;
						btnSave.Enabled = true;
						//Load the data table and display information
						gridTable = OrganizationHelper.CreateDataTable<CrmPlugin>(CrmPlugin.Columns, assembly.Plugins);
					}
					break;
				case CrmTreeNodeType.Plugin:
				case CrmTreeNodeType.WorkflowActivity:
					{
						CrmPlugin plugin = (CrmPlugin)node;
						btnSave.Enabled = true;
						//Load the data table and display information
						gridTable = OrganizationHelper.CreateDataTable<CrmPluginStep>(CrmPluginStep.Columns, plugin.Steps);
					}
					break;
				case CrmTreeNodeType.Step:
					{
						CrmPluginStep step = (CrmPluginStep)node;
						btnSave.Enabled = false;
						this.UpdateEnableButton(step.Enabled);

						this.toolEnable.Visible = true;
						this.mnuContextNodeEnable.Visible = true;

						this.toolUpdate.Visible = true;
						this.mnuContextNodeUpdate.Visible = true;

						//Load the data table and display information
						gridTable = OrganizationHelper.CreateDataTable<CrmPluginImage>(CrmPluginImage.Columns, step.Images);
					}
					break;
				case CrmTreeNodeType.Image:
					{
						this.toolUpdate.Visible = true;
						this.mnuContextNodeUpdate.Visible = true;
						CrmPluginImage image = (CrmPluginImage)node;
						btnSave.Enabled = false;
						//Load the data table and display information
						gridTable = null;
					}
					break;
				case CrmTreeNodeType.Message:
				case CrmTreeNodeType.MessageEntity:
					{
						toolUnregister.Enabled = false;
						mnuContextNodeUnregister.Enabled = false;
						btnSave.Enabled = false;
						CrmTreeNode treeNode = (CrmTreeNode)node;
						switch (treeNode.ChildNodeType)
						{
							case CrmTreeNodeType.Message:
								{
									gridTable = OrganizationHelper.CreateDataTable<CrmMessage>(CrmMessage.Columns,
										(CrmMessage[])treeNode.ToEntityArray(CrmTreeNodeType.Message));
								}
								break;
							case CrmTreeNodeType.MessageEntity:
								{
									gridTable = OrganizationHelper.CreateDataTable<CrmMessageEntity>(CrmMessageEntity.Columns,
										(CrmMessageEntity[])treeNode.ToEntityArray(CrmTreeNodeType.MessageEntity));
								}
								break;
							case CrmTreeNodeType.Step:
								{
									gridTable = OrganizationHelper.CreateDataTable<CrmPluginStep>(CrmPluginStep.Columns,
										(CrmPluginStep[])treeNode.ToEntityArray(CrmTreeNodeType.Step));
								}
								break;
							default:
								gridTable = null;
								break;
						}
					}
					break;
				default:

					throw new NotImplementedException("NodeType = " + node.NodeType.ToString());
			}

			//Update the properties grid
			{
				CrmTreeNode treeNode = node as CrmTreeNode;
				if (null == treeNode)
				{
					this.propGridEntity.SelectedObject = node;
				}
				else
				{
					this.propGridEntity.SelectedObject = treeNode.Entity;
				}
			}

			this.m_dataRowIndex = -1;
			this.m_dataRowId = Guid.Empty;
			if (gridTable == null)
			{
				grpGrid.Visible = false;
				splitterDisplay.Height = grpGrid.Bottom - splitterDisplay.Top;
			}
			else
			{
				grpGrid.Visible = true;
				splitterDisplay.Height = grpGrid.Top - grpPlugins.Margin.Bottom - grpGrid.Margin.Top - splitterDisplay.Top;

				//Create the list of values

				//Create the new DataSet
				DataSet set = new DataSet("Grid");
				set.Tables.Add(gridTable);

				grvData.DataSource = set.DefaultViewManager;
				grvData.DataMember = gridTable.TableName;
				grvData.Columns["Id"].Visible = false;
			}
		}
        */
        /*
		private void LoadNodes()
		{
			this.LoadNodes(this.m_currentView);
		}

        
		private void LoadNodes(CrmViewType view)
		{
			ToolStripItem currentCheckedItem = null;
			ToolStripItem newCheckedItem = null;

			foreach (ToolStripItem item in toolView.DropDownItems)
			{
				if (item.Tag != null && item.Tag.GetType() == typeof(CrmViewType))
				{
					PropertyInfo checkedProp = item.GetType().GetProperty("Checked", typeof(bool));
					if (checkedProp != null)
					{
						if ((bool)checkedProp.GetValue(item, null))
						{
							currentCheckedItem = item;
						}
						else if ((CrmViewType)item.Tag == view)
						{
							newCheckedItem = item;
						}
					}
				}

				if (currentCheckedItem != null && newCheckedItem != null)
				{
					break;
				}
			}

			//Create the new view
			this.Enabled = false;
			try
			{
				switch (view)
				{
					case CrmViewType.Assembly:
						this.m_rootNodeList = null;
						this.m_stepParentList = null;
						this.m_viewNodeList = null;

						List<ICrmTreeNode> nodes = new List<ICrmTreeNode>();
						foreach (CrmPluginAssembly assembly in this.Organization.Assemblies)
						{
							// If the same assembly name used for any other custom plugin assembly then that need to be added
							if (!(assembly.Name == CrmServiceEndpoint.ServiceBusPluginAssemblyName && assembly.CustomizationLevel == 0))
							{
								nodes.Add(assembly);
							}
						}

						nodes.AddRange(this.Organization.ServiceEndpoints.ToArray());
						trvExcelSheetContents.LoadNodes(nodes.ToArray());
						break;
					case CrmViewType.Entity:
					case CrmViewType.Message:
						{
							//Create the Root Node List
							if (null == this.m_rootNodeList)
							{
								this.m_rootNodeList = new Dictionary<string, CrmTreeNode>();
							}
							else
							{
								this.m_rootNodeList.Clear();
							}

							//Create the Step Parent Node List
							if (null == this.m_stepParentList)
							{
								this.m_stepParentList = new Dictionary<Guid, Guid>();
							}
							else
							{
								this.m_stepParentList.Clear();
							}

							//Create the View Node List
							if (null == this.m_viewNodeList)
							{
								this.m_viewNodeList = new Dictionary<Guid, Guid>();
							}
							else
							{
								this.m_viewNodeList.Clear();
							}

							//Retrieve the of steps
							foreach (CrmPluginStep step in this.Organization.Steps)
							{
								if (step.MessageId != Guid.Empty)
								{
									CrmTreeNode parentNode = this.CreateCrmTreeNodes(view,
										step.MessageId, step.MessageEntityId, false);

									parentNode.AddChild(step);
									this.m_stepParentList.Add(step.StepId, parentNode.NodeId);
								}
							}

							CrmTreeNode[] nodeList = new CrmTreeNode[this.m_rootNodeList.Count];
							this.m_rootNodeList.Values.CopyTo(nodeList, 0);

							trvExcelSheetContents.LoadNodes(nodeList);
						}
						break;
					default:
						throw new NotImplementedException("View = " + view.ToString());
				}

				this.m_currentView = view;

				if (currentCheckedItem != null)
				{
					currentCheckedItem.GetType().GetProperty("Checked",
						typeof(bool)).SetValue(currentCheckedItem, false, null);
				}

				if (newCheckedItem != null)
				{
					newCheckedItem.GetType().GetProperty("Checked",
						typeof(bool)).SetValue(newCheckedItem, true, null);
				}
			}
			catch (Exception ex)
			{
				ErrorMessage.ShowErrorMessageBox(this, "Unable to change the view", "View Error", ex);
			}
			finally
			{
				this.Enabled = true;
			}
		}

		private CrmTreeNode CreateCrmTreeNodes(CrmViewType view, Guid messageId, Guid messageEntityId, bool addToTree)
		{
			if (Guid.Empty == messageId)
			{
				throw new ArgumentException("Invalid Guid", "messageId");
			}

			CrmTreeNode rootNode, childNode;
			switch (view)
			{
				case CrmViewType.Message:
					{
						rootNode = new CrmTreeNode(this.m_org.Messages[messageId]);
						if (Guid.Empty == messageEntityId)
						{
							childNode = new CrmTreeNode(new CrmMessageEntity(Organization, messageId, Guid.Empty,
								"none", "none", CrmPluginStepDeployment.Both, null, null));
						}
						else
						{
							childNode = new CrmTreeNode(this.m_org.MessageEntities[messageEntityId]);
						}
					}
					break;
				case CrmViewType.Entity:
					{
						if (Guid.Empty == messageEntityId)
						{
							rootNode = new CrmTreeNode(new CrmMessageEntity(Organization, messageId, Guid.Empty, "none", "none",
								CrmPluginStepDeployment.Both, null, null));
						}
						else
						{
							rootNode = new CrmTreeNode(this.m_org.MessageEntities[messageEntityId]);
						}
						childNode = new CrmTreeNode(this.m_org.Messages[messageId]);
					}
					break;
				default:
					throw new NotImplementedException("View = " + view.ToString());
			}

			Guid rootNodeId = rootNode.NodeId;
			Guid childNodeId = childNode.NodeId;

			if (this.m_rootNodeList.ContainsKey(rootNode.NodeText))
			{
				rootNode = this.m_rootNodeList[rootNode.NodeText];
			}
			else
			{
				rootNode.NodeId = Guid.NewGuid();
				this.m_rootNodeList.Add(rootNode.NodeText, rootNode);

				if (addToTree)
				{
					trvExcelSheetContents.AddNode(Guid.Empty, rootNode);
				}
			}

			if (rootNode.HasChild(childNode.NodeText))
			{
				childNode = (CrmTreeNode)rootNode[childNode.NodeText];
			}
			else
			{
				childNode.NodeId = Guid.NewGuid();
				rootNode.AddChild(childNode);

				if (addToTree)
				{
					trvExcelSheetContents.AddNode(rootNode.NodeId, childNode);
				}
			}

			if (!this.m_viewNodeList.ContainsKey(rootNodeId))
			{
				this.m_viewNodeList.Add(rootNodeId, rootNode.NodeId);
			}

			if (!this.m_viewNodeList.ContainsKey(childNodeId))
			{
				this.m_viewNodeList.Add(childNodeId, childNode.NodeId);
			}

			return childNode;
		}

		private void UpdateEnableButton(bool currentlyEnabled)
		{
			string imageKey;
			if (currentlyEnabled)
			{
				toolEnable.Text = "&Disable";
				imageKey = "disable";
			}
			else
			{
				toolEnable.Text = "&Enable";
				imageKey = "enable";
			}

			toolEnable.Image = imlEnableImages.Images[imageKey];

			mnuContextNodeEnable.Text = toolEnable.Text;
			mnuContextNodeEnable.Image = toolEnable.Image;
		}

		/// <summary>
		/// Removes the given CrmTreeNode. If its parent does not have any other children, it will also be removed.
		/// </summary>
		/// <param name="nodeId">Node to be removed</param>
		private void RemoveCrmTreeNodesCascadeUp(CrmTreeNode node)
		{
			if (null == node)
			{
				throw new ArgumentNullException("node");
			}

			//Check if we are going to be removing this node
			while (null != node && 0 == node.ChildCount)
			{
				//Retrieve the parent node
				CrmTreeNode parentNode;
				if (Guid.Empty == node.ParentNodeId)
				{
					parentNode = null;

					//This is a root element, remove it from the list
					if (this.m_rootNodeList.ContainsKey(node.NodeText))
					{
						this.m_rootNodeList.Remove(node.NodeText);
					}
				}
				else
				{
					parentNode = (CrmTreeNode)trvExcelSheetContents[node.ParentNodeId];
					parentNode.RemoveChild(node.NodeText);
				}

				//Remove the node from the tree
				trvExcelSheetContents.RemoveNode(node.NodeId);

				//Set the current node to be the parent node
				node = parentNode;
			}
		}
        */
        #endregion

        #region Private Classes & Enums
        private sealed class CrmEntitySorter : IComparer<ICrmTreeNode>
        {
            public int Compare(ICrmTreeNode node1, ICrmTreeNode node2)
            {
                if (node1 == null)
                {
                    return -1;
                }
                else if (node2 == null)
                {
                    return 1;
                }
                else if (node1.NodeType != node2.NodeType)
                {
                    return ((int)node1.NodeType - (int)node2.NodeType);
                }
                else if (node1.NodeType == CrmTreeNodeType.Step)
                {
                    CrmPluginStep step1 = (CrmPluginStep)node1;
                    CrmPluginStep step2 = (CrmPluginStep)node2;

                    if (step1.Rank == step2.Rank)
                    {
                        if (step1.CreatedOn == null && step2.CreatedOn == null)
                        {
                            return 0;
                        }
                        else if (step1.CreatedOn == null)
                        {
                            return -1;
                        }
                        else if (step2.CreatedOn == null)
                        {
                            return 1;
                        }
                        else
                        {
                            return DateTime.Compare((DateTime)step1.CreatedOn, (DateTime)step2.CreatedOn);
                        }
                    }
                    else if (step1.Rank < step2.Rank)
                    {
                        return -1;
                    }
                    else
                    {
                        return 1;
                    }
                }
                else
                {
                    return string.Compare(GetNodeText(node1), GetNodeText(node2), false);
                }
            }

            #region Private Helper Methods
            private string GetNodeText(ICrmTreeNode node)
            {
                if (node == null || node.NodeText == null)
                {
                    return null;
                }
                else
                {
                    return node.NodeText;
                }
            }
            #endregion
        }

        private enum CrmViewType
        {
            Assembly,
            Message,
            Entity
        }

        private sealed class CrmTreeNode : ICrmTreeNode
        {
            private ICrmEntity m_entity;
            private Guid m_parentNodeId = Guid.Empty;
            private Guid m_origNodeId;
            private Guid m_nodeId;
            private string m_nodeText;
            private CrmTreeNodeType m_type;
            private string m_typeLabel;
            private CrmTreeNodeImageType m_imageType;
            private CrmTreeNodeImageType m_selectedImageType;

            private CrmTreeNodeType m_childType = CrmTreeNodeType.None;
            private Dictionary<string, CrmTreeNode> m_childList = null;
            private Dictionary<Guid, CrmPluginStep> m_stepList = null;

            public CrmTreeNode(CrmMessage message)
            {
                if (message == null)
                {
                    throw new ArgumentNullException("message");
                }

                this.m_entity = message;
                this.m_nodeId = message.MessageId;
                this.m_nodeText = message.Name;
                this.m_type = CrmTreeNodeType.Message;
                this.m_typeLabel = "Message";
                this.m_imageType = CrmTreeNodeImageType.Message;
                this.m_selectedImageType = CrmTreeNodeImageType.MessageSelected;

                this.m_origNodeId = this.m_nodeId;

                this.UpdateNodeText();
            }

            public CrmTreeNode(CrmMessageEntity msgEntity)
            {
                if (msgEntity == null)
                {
                    throw new ArgumentNullException("entity");
                }

                this.m_entity = msgEntity;
                this.m_nodeId = msgEntity.MessageEntityId;
                if (string.IsNullOrEmpty(msgEntity.PrimaryEntity))
                {
                    this.m_nodeText = "No Entity";
                }
                else if (string.IsNullOrEmpty(msgEntity.SecondaryEntity) ||
                    msgEntity.SecondaryEntity.Equals("none", StringComparison.CurrentCultureIgnoreCase))
                {
                    this.m_nodeText = msgEntity.PrimaryEntity;
                }
                else
                {
                    this.m_nodeText = string.Format("{0} / {1}", msgEntity.PrimaryEntity, msgEntity.SecondaryEntity);
                }
                this.m_type = CrmTreeNodeType.MessageEntity;
                this.m_typeLabel = "Entity";
                this.m_imageType = CrmTreeNodeImageType.MessageEntity;
                this.m_selectedImageType = CrmTreeNodeImageType.MessageEntitySelected;

                this.m_origNodeId = this.m_nodeId;

                this.UpdateNodeText();
            }

            public CrmTreeNode(Guid nodeId, string text, CrmTreeNodeType type,
                CrmTreeNodeImageType imageType, CrmTreeNodeImageType selectedImageType)
            {
                if (text == null)
                {
                    throw new ArgumentNullException("text");
                }

                this.m_entity = null;
                this.m_nodeId = nodeId;
                this.m_nodeText = text;
                this.m_type = type;
                this.m_imageType = imageType;
                this.m_selectedImageType = selectedImageType;

                this.m_origNodeId = this.m_nodeId;

                this.UpdateNodeText();
            }

            public void AddChild(CrmPluginStep node)
            {
                if (node == null)
                {
                    throw new ArgumentNullException("node");
                }
                else if (this.m_childType != CrmTreeNodeType.None && this.m_childType != node.NodeType)
                {
                    throw new ArgumentException("Child Node Type has already been determined");
                }
                else if (this.m_childType == CrmTreeNodeType.None)
                {
                    this.m_childType = node.NodeType;
                    this.m_stepList = new Dictionary<Guid, CrmPluginStep>();
                }

                this.m_stepList.Add(node.NodeId, node);
            }

            public void AddChild(CrmTreeNode node)
            {
                if (node == null)
                {
                    throw new ArgumentNullException("node");
                }
                else if (this.m_childType != CrmTreeNodeType.None && this.m_childType != node.NodeType)
                {
                    throw new ArgumentException("Child Node Type has already been determined");
                }
                else if (this.m_childType == CrmTreeNodeType.None)
                {
                    this.m_childType = node.NodeType;
                    this.m_childList = new Dictionary<string, CrmTreeNode>();
                }

                node.m_parentNodeId = this.m_nodeId;
                this.m_childList.Add(node.NodeText, node);
            }

            public void RemoveChild(Guid key)
            {
                if (this.m_stepList == null)
                {
                    throw new ArgumentException("Id is not in the list");
                }
                else
                {
                    this.m_stepList.Remove(key);
                }
            }

            public void RemoveChild(string key)
            {
                if (this.m_childList == null)
                {
                    throw new ArgumentException("Id is not in the list");
                }
                else
                {
                    this.m_childList.Remove(key);
                }
            }

            public bool HasChild(Guid id)
            {
                if (this.m_stepList != null)
                {
                    return this.m_stepList.ContainsKey(id);
                }
                else
                {
                    return false;
                }
            }

            public bool HasChild(string nodeText)
            {
                if (this.m_childList != null)
                {
                    return this.m_childList.ContainsKey(nodeText);
                }
                else
                {
                    return false;
                }
            }

            public CrmPluginStep this[Guid id]
            {
                get
                {
                    return this.m_stepList[id];
                }
            }

            public CrmTreeNode this[string text]
            {
                get
                {
                    return this.m_childList[text];
                }
            }

            public CrmTreeNodeType ChildNodeType
            {
                get
                {
                    return this.m_childType;
                }
            }

            public ICrmEntity[] ToEntityArray(CrmTreeNodeType type)
            {
                if (this.m_childType == CrmTreeNodeType.None)
                {
                    this.m_childType = type;
                }
                else if (this.m_childType != type)
                {
                    throw new ArgumentNullException("Child type already determined");
                }

                ICrmEntity[] childList;
                int childIndex = 0;
                switch (type)
                {
                    case CrmTreeNodeType.Message:
                        childList = new CrmMessage[this.m_childList.Count];
                        foreach (CrmTreeNode childNode in this.m_childList.Values)
                        {
                            childList[childIndex++] = (CrmMessage)childNode.Entity;
                        }
                        break;
                    case CrmTreeNodeType.MessageEntity:
                        childList = new CrmMessageEntity[this.m_childList.Count];
                        foreach (CrmTreeNode childNode in this.m_childList.Values)
                        {
                            childList[childIndex++] = (CrmMessageEntity)childNode.Entity;
                        }
                        break;
                    case CrmTreeNodeType.Step:
                        childList = new CrmPluginStep[this.m_stepList.Count];
                        this.m_stepList.Values.CopyTo((CrmPluginStep[])childList, 0);
                        break;
                    default:
                        throw new NotImplementedException("Type = " + type.ToString());
                }

                return childList;
            }

            public Guid ParentNodeId
            {
                get
                {
                    return this.m_parentNodeId;
                }
            }

            public Guid OriginalNodeId
            {
                get
                {
                    return this.m_origNodeId;
                }
            }

            public int ChildCount
            {
                get
                {
                    if (null != this.m_childList)
                    {
                        return this.m_childList.Count;
                    }
                    else if (null != this.m_stepList)
                    {
                        return this.m_stepList.Count;
                    }
                    else
                    {
                        return 0;
                    }
                }
            }

            #region ICrmTreeNode Members
            public ICrmEntity Entity
            {
                get
                {
                    return this.m_entity;
                }
            }

            public Guid NodeId
            {
                get
                {
                    return this.m_nodeId;
                }
                set
                {
                    this.m_nodeId = value;

                    if (null != this.m_childList)
                    {
                        foreach (CrmTreeNode childNode in this.m_childList.Values)
                        {
                            childNode.m_parentNodeId = value;
                        }
                    }
                }
            }

            public string NodeText
            {
                get
                {
                    return this.m_nodeText;
                }
            }

            public CrmTreeNodeType NodeType
            {
                get
                {
                    return this.m_type;
                }
            }

            public string NodeTypeLabel
            {
                get
                {
                    return this.m_typeLabel;
                }
            }

            public ICrmTreeNode[] NodeChildren
            {
                get
                {
                    if (this.m_stepList != null)
                    {
                        CrmPluginStep[] nodeList = new CrmPluginStep[this.m_stepList.Count];
                        this.m_stepList.Values.CopyTo(nodeList, 0);

                        return nodeList;
                    }
                    else if (this.m_childList != null)
                    {
                        CrmTreeNode[] nodeList = new CrmTreeNode[this.m_childList.Count];
                        this.m_childList.Values.CopyTo(nodeList, 0);

                        return nodeList;
                    }
                    else
                    {
                        return new ICrmTreeNode[0];
                    }
                }
            }

            public CrmTreeNodeImageType NodeImageType
            {
                get
                {
                    return this.m_imageType;
                }
            }

            public CrmTreeNodeImageType NodeSelectedImageType
            {
                get
                {
                    return this.m_selectedImageType;
                }
            }
            #endregion

            #region Private Helpers
            private void UpdateNodeText()
            {
                string prefix;
                switch (this.m_type)
                {
                    case CrmTreeNodeType.Message:
                        prefix = "Message";
                        break;
                    case CrmTreeNodeType.MessageEntity:
                        prefix = "Entity";
                        break;
                    default:
                        throw new NotImplementedException("NodeType = " + this.m_type.ToString());
                }

                this.m_nodeText = string.Format("({0}) {1}", prefix, this.m_nodeText);
            }
            #endregion
        }
        #endregion

        EntityContainer entityContainer;


        private void btnLoadExcel_Click(object sender, EventArgs e)
        {
            //TODO: Add icon for btnLoadExcel button
            DialogResult dialogResult = dlgLoadExcel.ShowDialog();

            if (dialogResult == DialogResult.OK || dialogResult == DialogResult.Yes)
            {
                Exception exception;
                if (ExcelParser.ParseExcelSheet(dlgLoadExcel.FileName, out exception, out entityContainer))
                {

                    LoadTreeView();

                    ActionButtonsEnabled = true;
                }
                else
                {
                    ActionButtonsEnabled = false;
                    ErrorMessage.ShowErrorMessageBox(this, "An error occurred while parsing excel sheet", "Parser", exception);
                }

            }
        }

        public bool ActionButtonsEnabled
        {
            set
            {
                btnUpdateCRM.Enabled = value;
                btnCreateDocumentation.Enabled = value;
                txtSolutionName.Enabled = value;
            }
        }

        private void trvExcelSheetContents_AfterCheck(object sender, TreeViewEventArgs e)
        {
            //Entity Node
            if (e.Node.Nodes.Count > 0)
            {
                entityContainer.Entities.Find(entity => entity.Metadata.SchemaName == e.Node.Tag.ToString()).IncludeInTransaction
                    = e.Node.Checked;

                foreach (TreeNode childNode in e.Node.Nodes)
                {
                    childNode.Checked = e.Node.Checked;
                    entityContainer.Entities.Find(entity => entity.Metadata.SchemaName == e.Node.Tag.ToString()).Attributes.Find(attribute => attribute.Attribute.SchemaName == childNode.Tag.ToString()).IncludeInTransaction = childNode.Checked;
                }
            }
            //attribute entity
            else
            {
                entityContainer.Entities.Find(entity => entity.Metadata.SchemaName == e.Node.Parent.Tag.ToString()).Attributes.Find(attribute => attribute.Attribute.SchemaName == e.Node.Tag.ToString()).IncludeInTransaction = e.Node.Checked;
            }
        }

        //private void trvExcelSheetContents_AfterSelect(object sender, TreeViewEventArgs e)
        //{
        //    if (e.Node.Nodes.Count > 0)
        //        propGridEntity.SelectedObject = entityContainer.Entities.Find(entity => entity.Metadata.SchemaName == e.Node.Tag.ToString());
        //    else
        //        propGridEntity.SelectedObject = entityContainer.FlatAttributes.Find(att => att.Attribute.SchemaName == e.Node.Tag.ToString());
        //}

        #region Action Button Handlers
        //TODO: Add icon for btnUpdateCRM button
        private void btnUpdateCRM_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtSolutionName.Text))
            {
                MessageBox.Show("Solution name must be provided!");
                return;
            }

            m_mainForm.ProgressIndicator.Initialize(0, entityContainer.Entities.Count, 0, "Updating CRM");
            foreach (var entity in entityContainer.Entities)
            {
                TreeNode entityNode = trvExcelSheetContents.Nodes.Find(entity.Metadata.SchemaName, false)[0];

                try
                {
                    WebServiceConnector.CreateEntity(entity, m_org.OrganizationService, txtSolutionName.Text);
                    entityNode.ForeColor = Color.Green;
                    entityNode.ToolTipText = string.Empty;

                    foreach (var attribute in entity.Attributes)
                    {
                        TreeNode attributeNode = entityNode.Nodes.Find(attribute.Attribute.SchemaName, false)[0];
                        try
                        {
                            WebServiceConnector.CreateAttribute(attribute, m_org.OrganizationService, txtSolutionName.Text);
                            attributeNode.ForeColor = Color.Green;
                            attributeNode.ToolTipText = string.Empty;
                        }
                        catch (Exception ex)
                        {
                            //TODO: color the attribute node with red color and display error message as a tooltip
                            attributeNode.ForeColor = Color.Red;
                            attributeNode.ToolTipText = ex.Message;
                        }
                    }
                }
                catch (Exception ex)
                {
                    //TODO: color the entity node with red color and display error message as a tooltip
                    entityNode.ForeColor = Color.Red;
                    entityNode.ToolTipText = ex.Message;
                }

                m_mainForm.ProgressIndicator.Increment();
            }

            m_mainForm.ProgressIndicator.Complete();

            MessageBox.Show("Updating CRM has completed, green color indicates success, red indicates failure. \r\nPlease move the mouse over red nodes to see the exact error.", "CRM Update Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);

        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            //TODO: save changes back to entityContainer
            ExcelParser.MapFlatAttributesToEntities(entityContainer);

            LoadTreeView();
        }

        private void LoadTreeView()
        {
            trvExcelSheetContents.Nodes.Clear();

            foreach (var entity in entityContainer.Entities)
            {
                TreeNode entityNode = new TreeNode(entity.Metadata.DisplayName.LocalizedLabels[0].Label);
                entityNode.ImageIndex = 0;
                entityNode.Tag = entity.Metadata.SchemaName;
                entityNode.Checked = true;
                entityNode.Name = entity.Metadata.SchemaName;

                foreach (var attribute in entity.Attributes)
                {
                    TreeNode attributeNode = new TreeNode(attribute.Attribute.DisplayName.LocalizedLabels[0].Label);
                    attributeNode.Tag = attribute.Attribute.SchemaName;
                    attributeNode.ImageIndex = 1;
                    attributeNode.Checked = true;
                    attributeNode.Name = attribute.Attribute.SchemaName;

                    entityNode.Nodes.Add(attributeNode);
                }
                trvExcelSheetContents.Nodes.Add(entityNode);
            }
            trvExcelSheetContents.ExpandAll();
        }

        private void btnCreateDocumenation_Click(object sender, EventArgs e)
        {
            DialogResult dr = dlgSaveDocumentation.ShowDialog();

            if (dr == DialogResult.OK || dr == DialogResult.Yes)
            {
                try
                {
                    DocumentGenerator.GenerateDocument(dlgSaveDocumentation.FileName, entityContainer);

                    MessageBox.Show("Document is generated, please check path: "+dlgSaveDocumentation.FileName, "CRM Update Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                catch (Exception)
                {

                    throw;
                }
            }
            //TODO: Add icon for btnCreateDocumenation button
        }
        #endregion Action Button Handlers


    }
}
